﻿using SkiaSharp;
using System;
using System.IO;

namespace ImgClip
{
    /// <summary>
    /// 
    /// </summary>
    public class SkiaPocess : IDisposable
    {
        private SKBitmap _source = null, _bitmap = null, _watebitmap;
        private readonly Resolve _resolve;

        /// <summary>
        /// 
        /// </summary>
        public SKEncodedImageFormat Format { get; private set; } = SKEncodedImageFormat.Jpeg;


        public SkiaPocess(Stream stream, Resolve resolve) : this(stream, resolve, null)
        {
            //_source = SKBitmap.Decode(stream);
            //_resolve = resolve;
        }

        public SkiaPocess(Stream stream, Resolve resolve, Stream watermark)
        {
            stream.Position = 0; 
            _source = SKBitmap.Decode(stream);
            _resolve = resolve;
            if (watermark != null)
            {
                watermark.Position = 0;
                _watebitmap = SKBitmap.Decode(watermark);
            }
        }



        /// <summary>
        /// Initialize the image size
        /// </summary>
        /// <returns></returns>
        private SkiaPocess Init()
        {
            _bitmap = _source;
            return this;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        private SkiaPocess Crop()
        {
            if (_resolve.IsCrop)
            {
                var rectangle = CroppingRectangle.CropCalc(_source, _resolve.CropGravity, _resolve.CropWidth, _resolve.CropHeight, _resolve.CropOffsetX, _resolve.CropOffsetY);
                if (rectangle.IsEligible)
                {
                    _bitmap = new SKBitmap((int)rectangle.Dest.Width, (int)rectangle.Dest.Height);
                    using var canvas = new SKCanvas(_bitmap);
                    canvas.DrawBitmap(_source, rectangle.Source, rectangle.Dest);
                }
            }
            return this;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        private SkiaPocess Resize()
        {
            if (_resolve.IsResize)
            {
                _source = _bitmap;
                var rectangle = CroppingRectangle.ResizeCalc(_source, _resolve.ResizeType, _resolve.IsEnlarge, _resolve.Width, _resolve.Height);
                if (rectangle.IsEligible)
                {
                    _bitmap = new SKBitmap((int)rectangle.Dest.Width, (int)rectangle.Dest.Height);
                    using var canvas = new SKCanvas(_bitmap);
                    if (rectangle.IsPad)
                    {
                        if (SKColor.TryParse(_resolve.Background, out SKColor _bgcolor))
                            canvas.DrawColor(_bgcolor);
                        canvas.DrawBitmap(_source, rectangle.Source);
                    }
                    else
                        canvas.DrawBitmap(_source, rectangle.Source, rectangle.Dest);
                }
            }
            return this;
        }

        private SkiaPocess Rotate()
        {
            if (_resolve.IsRotate)
            {
                _source = _bitmap;
                double radian = _resolve.RotateAngle * Math.PI / 180.0;
                double cos = Math.Cos(radian);
                double sin = Math.Sin(radian);

                var width = Math.Abs(cos * _source.Width) + Math.Abs(sin * _source.Height);
                var height = Math.Abs(cos * _source.Height) + Math.Abs(sin * _source.Width);
                _bitmap = new SKBitmap((int)width, (int)height);
                using var canvas = new SKCanvas(_bitmap);
                canvas.RotateDegrees(_resolve.RotateAngle, _bitmap.Width / 2, _bitmap.Height / 2);
                canvas.DrawBitmap(_source, (int)(width - _source.Width) / 2, (int)(height - _source.Height) / 2);
            }
            return this;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        private SkiaPocess Watermark()
        {
            if (_resolve.IsWatermark && _watebitmap != null)
            {
                var rectangle = CroppingRectangle.WatermarkCalc(_watebitmap, _resolve.WmPosition, _bitmap.Width, _bitmap.Height, _resolve.WmOffsetX, _resolve.WmOffsetY);
                if (rectangle.IsEligible)
                {
                    using var canvas = new SKCanvas(_bitmap);
                    rectangle.Sources.ForEach(rect =>
                    {
                        canvas.DrawBitmap(_watebitmap, rect);
                    });
                }
            }
            return this;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public SKData FinishAsync()
        {
            Init().Crop().Resize().Watermark().Rotate();

            return SKImage.FromBitmap(_bitmap).Encode(this.Format, _resolve.Quality);
        }

        public void Dispose()
        {
            _source?.Dispose();
            _bitmap?.Dispose();
            _watebitmap?.Dispose();
            _source = null;
            _bitmap = null;
            _watebitmap = null;
            GC.SuppressFinalize(this);
        }


    }
}
